/*
 * Copyright 2011-2012 SUPSI
 * Author: Raffaello Giulietti
 */

package comint03.tokenizer;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Locale;

public class Token {

    public static enum Type {
        
        // Put keywords between Bok_* and Eok_*.
        // Except for case, the spelling of the enums and the keywords shall be the same.
        // They are put in the reserved map by the class initializer.
        // The Bok_* and Eok_* marker names have been chosen to reduce the risk of clashes with real-world keywords.
        
        Bok_7cc9d33489e99a8b210379e7a3a3b2e7b102fd09, // begin of keywords block
        
        Nil,
        
        Eok_7cc9d33489e99a8b210379e7a3a3b2e7b102fd09, // end of keywords block

        Ident, Num, String,
        Semicolon, Comma, Ref,		// ; , ->
        OpenParen, CloseParen,		// []
        OpenBrace, CloseBrace,		// {}
        Assoc,						// :
        Tag,						// #
        
        Eos,
        Unknown,
    }

    private static final HashMap<String, Token> reserved = new HashMap<String, Token>();

    private final Type type;
    private final String name;
    private final BigDecimal num;

    static {
        Type[] values = Type.values();
        for (int i = Type.Bok_7cc9d33489e99a8b210379e7a3a3b2e7b102fd09.ordinal() + 1; i < Type.Eok_7cc9d33489e99a8b210379e7a3a3b2e7b102fd09.ordinal(); ++i)
            reserved.put(values[i].name().toLowerCase(Locale.US), new Token(values[i]));
    }

    private Token(Type type, BigDecimal num, String name) {
        this.type = type;
        this.name = name;
        this.num = num;
    }

    private Token(Type type) {
        this(type, null, null);
    }

    public Type type() {
        return type;
    }

    public String name() {
        return name;
    }

    public BigDecimal num() {
        return num;
    }

    static Token ident(String name) {
        Token token = reserved.get(name);
        return
            token != null ?
                new Token(token.type(), null, null) :
                new Token(Type.Ident, null, name);
    }

    static Token simple(Type type) {
        return new Token(type, null, null);
    }

    static Token num(BigDecimal num) {
        return new Token(Type.Num, num, null);
    }

    static Token string(String s) {
        return new Token(Type.String, null, s);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(80);
        sb.append(Token.class.getSimpleName())
            .append(" [type=")
            .append(type());
        if (name() != null)
            sb.append(", name=").append(name());
        if (num() != null)
            sb.append(", num=").append(num());
        sb.append("]");
        return sb.toString();
    }

}
